#include "user_lib.h"
#include "../kernel/const.h"

#define RIGHT_READ_ALL ((fe.attribut >> 2) & 1)
#define RIGHT_EXECUTE_ALL (fe.attribut  & 1)
#define RIGHT_READ_OWNER ((fe.attribut >> 6) & 1)
#define RIGHT_EXECUTE_OWNER ((fe.attribut << 4)  & 1)
#define ADMIN (syscall_user(SYSCALL_GETCURRENTUID) == 0)
#define FILE_BELONG_OWNER (syscall_user(SYSCALL_GETCURRENTUID) == fe.uid)

void printInt(uint nb, int base)
{
	uint nbProc =nb, nbDigit =0;
	while(nbProc >= base)
	{
		nbProc = divide(nbProc,base);				// Calcul le nombre de digit
		nbDigit ++;
	}
	nbDigit +=1;   									// nombre de digit réel
	while(nbDigit >0)								// transforme 1 en 10, 2 en 100
	{
		int valDig =0, valDigExx =1, tmpNbDig =0;
		tmpNbDig = nbDigit -1;
		while(tmpNbDig >0)
		{
			valDigExx = valDigExx * base;
			tmpNbDig --;
		}
		valDig = divide(nb,valDigExx);				// trouve le digit
		nb = nb - valDig * valDigExx;				// soustrait la partie traitée
		if ((valDig >9) & (base == 16))				// Si la base 16 est choisie 
			valDig = valDig + DIFF_ASCII_0_A;		// Affiche les lettres A à F 
		printChar(valDig + ASCII_ZERO);				// Affiche le digit correspondant
		nbDigit --;
	}
}

void printChar(char c)
{
	syscall_user(SYSCALL_PRINTCHAR,(int)c);
}

void printString(char* str)
{
	int i;
	for(i=0; str[i]; i++)
	{
		printChar(str[i]);
		if (str[i] == '\n') 
			printChar(13);							// line feed si retour a la ligne
	}
}

/* readChar() 
 *
 * When a key is pressed, al contains the ASCII code for the key read
 * (ah contains the keyboard scan code)
 */
char readChar()
{
	char k;											// store al (8 lsb)
	k = syscall_user(SYSCALL_READCHAR);
	return k;
}

void readString(char *string)
{
	char k;
	do												// store al (8 lsb) 
	{
	  k = readChar();
	  printChar(k);
	  *string++ = k;
	}
	while(k != 13);									// attend carriage return 
	printChar(10);									// 10 pour line feed 
	*string = 0;									// 0 pour fin de chaine
}

/* strlen (char *str)
 *fonctionne qui calcule la taille d'une chaine des caracteres
 */
int strlen (char *str)
{
	int len = 0;
	while (*str != '\0')
	{
		str++;
		len++;
	}
	return len;
}

/* strcat(char *destination, char *source)
 *fonctionne qui fait la concatenation des deux chaines des caracteres 
 */
char strcat(char *destination, char *source)
{
	char *str = destination;

	while (*str != '\0')
	{
		str++;
	}
	while (*source != '\0')
	{
		*str = *source;
		str++;
		source++;
	}
	*str = '\0';
	return str;
}

char* strcpy(char *dest,  char *src)
{
	char *save = dest;
	while(*dest++ = *src++);
	return save;
}

int strcmp (char *p1, char *p2){
	int tmp=0;

	while(p1[tmp] != '\0'){
		if(p2[tmp] == '\0') return 0;
		if(p1[tmp] != p2[tmp]) return 0;
		tmp ++;
	}
	if(p2[tmp] != '\0') return 0;
	return 1;
}

/*
	Fonction qui convert un string en integer
*/
int atoi(char *str)
{
	int number = 0;
	if(!str)
	{
		printString("Enter valid string\n");
	}
	else
	{
		while(*str && (*str >= '0') && (*str <= '9'))
		{
			number = number * 10 + (*str - '0');
			*str++;
		}
	} 
	return number;
}

/*
	Fonction qui efface tout l'écran, en y ajoutant le caractère NOIR sur GRIS ' '
   memputb permet d'écrire directement dans la mémoire vidéo texte
*/
void clearScreen(void) 
{
	int i=0, j=0, k=0;
	for (j=0;j<NBR_LIGNE;j++)
	{
		for (i=0;i<NBR_COL*2;i+=2) 
		{
 			syscall_user(SYSCALL_MEMPUTB,VIDEO_ADDR,i+j*NBR_COL*2,' ');
 			syscall_user(SYSCALL_MEMPUTB,VIDEO_ADDR,i+1+j*NBR_COL*2,NOIR_SUR_GRIS);
		}
	}
	syscall_user(SYSCALL_SETCURSOR,0,0);						// position du curseur 0,0
}

void waitKey() 
{
	printString("Press any key to continue"); 
	readChar(); 
	printString("\n");
}


void removeFile(char *arg1) 
{
	char car;
	File_entry fe;
	if (syscall_user(SYSCALL_GETSTAT ,arg1,&fe)) 				// test si le fichier existe
	{
		if (syscall_user(SYSCALL_GETCURRENTUID) == fe.uid)
		{
			printString("Do you want to erase "); printString(arg1); printString(" (y or n) ?");
			car = readChar();	
			if ((car == 'z') | (car == 'Z'))						// clavier QWERTY 
			{
				syscall_user(SYSCALL_REMOVEFILE,arg1);
				printString("\nFile "); printString(arg1); printString(" erased\n");
			}
			else 
				printString("\n");
		}
		else 
			printString("\nNot allowed to erase this file\n");
	}
	else 
		printString("\nError. File not found\n");
}

void listFiles(void) 
{
	uchar att;	
	char buffer[512],login[40];
  	int index = FE_SECT,i,maxLengthFileName=0, maxLengthLogin=0;
	File_entry fe;
	
	i=0;
	while(!syscall_user(SYSCALL_GETNEXTFILE,&fe,&index)) // maximum taille nom fichier
	{
		if (maxLengthFileName < strlen(fe.name))		 // pour affichage droit
			maxLengthFileName =  strlen(fe.name);

		syscall_user(SYSCALL_GETLOGIN,i++,&login);
		if (maxLengthLogin < strlen(login))
			maxLengthLogin =  strlen(login);
	}

	index = FE_SECT;
	while(!syscall_user(SYSCALL_GETNEXTFILE,&fe,&index)) // tant qu'il y a des fichiers
	{
		if (fe.name[0])									//   passe le bit 4 --> attribut bit 7 6 5 4 2 1 0
		{												//	  							     R W X R W X
			printChar(' ');								//							   ADMI    USR  ALL
			for (i=6;i>=0;i--) 
			{
				att = ((fe.attribut)>>i) &1;				// isole les bits de l'attribut
	
				if (i==3) 								
					printChar(' ');							
				else if (att) 
					printChar('x');
				else 
					printChar('-');
			}
			printChar(' ');	printChar(' ');	
		
			//		printString(" NAME :");
			printString(fe.name);

			for(i=0;i< maxLengthFileName+2 - strlen(fe.name);i++)
	  			printChar(' ');

			syscall_user(SYSCALL_GETLOGIN,fe.uid,&login);
				printString(login);

			for(i=0;i< maxLengthLogin+2 - strlen(login);i++)
	  			printChar(' ');

			//		printString(" SIZE :");
			printInt(fe.sizeH,10);
			//		printString(" @SECTOR :");printInt(index,10);
			printString("\n");
		}
	}
}

void printFile(char *arg1) 
{
	int i;
	char buffer[FILE_SIZE];
	File_entry fe;
	if (syscall_user(SYSCALL_GETSTAT ,arg1,&fe)) 								// test si le fichier existe
	{
		if ((FILE_BELONG_OWNER & RIGHT_READ_OWNER) | RIGHT_READ_ALL | ADMIN) 	// test les droits read
		{	
			syscall_user(SYSCALL_READFILE,arg1,buffer);		
			printString(buffer);
		}
		else 
			printString("\nNot allowed to read this file\n");

	}
	else 
		printString("\nError. File not found\n");
}

void exec(char *bin, uint seg)
{
	File_entry fe;
		if (syscall_user(SYSCALL_GETSTAT ,bin,&fe)) 								// test si le fichier existe
	{

		if ((FILE_BELONG_OWNER & RIGHT_EXECUTE_OWNER) | RIGHT_EXECUTE_ALL | ADMIN) 	// test droit exec 
			syscall_user(SYSCALL_EXEC, bin, seg);
		else 
			printString("\nNot allowed to execute this file\n");
	}
	else 
		printString("\nError. File not found\n");
}


int getTicks()
{
	return syscall_user(SYSCALL_GETTICKS);
}

void getStringBackSpace(char *bufId) 
{
	char car =0; int i=0;
	while (car != RETURN) {
		car = readChar();
		printChar(car);
		bufId[i++] = car;
		if (car == BACKSPACE) 
		{
			printChar(' ');
			printChar(BACKSPACE);		// retour en arrière du curseur
			bufId[i--] = 0;
			if (i)						// si i est positif
				i--;
			else
				printChar(' ');			// empeche que le curseur ai trop loin
		}
	}
	bufId[i-1] = 0;
}

